/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-06-10     liuduanfei   first version
 */

#include <stdint.h>
#include <rtthread.h>
#include "board.h"

#include "drv_uart.h"

/* The ICG area is filled with F by default, HRC = 16MHZ,
   Please modify this value as required */
#if defined ( __GNUC__ ) && !defined (__CC_ARM) /* GNU Compiler */
const uint32_t u32ICG[] __attribute__((section(".icg_sec"))) =
#elif defined (__CC_ARM)
const uint32_t u32ICG[] __attribute__((at(0x400))) =
#elif defined (__ICCARM__)
__root const uint32_t u32ICG[] @ 0x400 =
#else
#error "unsupported compiler!!"
#endif
{
    /* ICG 0~ 3 */
    0xFFFFFFFFUL,
    0xFFFFFFFFUL,
    0xFFFFFFFFUL,
    0xFFFFFFFFUL,
    /* ICG 4~ 7 */
    0xFFFFFFFFUL,
    0xFFFFFFFFUL,
    0xFFFFFFFFUL,
    0xFFFFFFFFUL,
};

/**
 * This is the timer interrupt service routine.
 */
void SysTick_Handler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    rt_tick_increase();

    /* leave interrupt */
    rt_interrupt_leave();
}

void System_Clock_Config(void)
{
    stc_clk_sysclk_cfg_t stcSysClkCfg;
    stc_clk_xtal_cfg_t stcXtalCfg;
    stc_clk_mpll_cfg_t stcMpllCfg;
    stc_sram_config_t stcSramConfig;

    MEM_ZERO_STRUCT(stcSysClkCfg);
    MEM_ZERO_STRUCT(stcXtalCfg);
    MEM_ZERO_STRUCT(stcMpllCfg);
    MEM_ZERO_STRUCT(stcSramConfig);

    /* Set bus clk div. */
    stcSysClkCfg.enHclkDiv  = ClkSysclkDiv1;
    stcSysClkCfg.enExclkDiv = ClkSysclkDiv2;
    stcSysClkCfg.enPclk0Div = ClkSysclkDiv1;
    stcSysClkCfg.enPclk1Div = ClkSysclkDiv2;
    stcSysClkCfg.enPclk2Div = ClkSysclkDiv4;
    stcSysClkCfg.enPclk3Div = ClkSysclkDiv4;
    stcSysClkCfg.enPclk4Div = ClkSysclkDiv2;
    CLK_SysClkConfig(&stcSysClkCfg);

    /* Config Xtal and Enable Xtal */
    stcXtalCfg.enMode = ClkXtalModeOsc;
    stcXtalCfg.enDrv = ClkXtalLowDrv;
    stcXtalCfg.enFastStartup = Enable;
    CLK_XtalConfig(&stcXtalCfg);
    CLK_XtalCmd(Enable);

    /* sram init include read/write wait cycle setting */
    stcSramConfig.u8SramIdx = Sram12Idx | Sram3Idx | SramHsIdx | SramRetIdx;
    stcSramConfig.enSramRC = SramCycle2;
    stcSramConfig.enSramWC = SramCycle2;
    SRAM_Init(&stcSramConfig);

    /* flash read wait cycle setting */
    EFM_Unlock();
    EFM_SetLatency(EFM_LATENCY_5);
    EFM_InstructionCacheCmd(Enable);
    EFM_Lock();

    /* MPLL config (XTAL / pllmDiv * plln / PllpDiv = 168M). */
    stcMpllCfg.pllmDiv = 1ul;
    stcMpllCfg.plln    = 42ul;
    stcMpllCfg.PllpDiv = 2ul;
    stcMpllCfg.PllqDiv = 2ul;
    stcMpllCfg.PllrDiv = 2ul;
    CLK_SetPllSource(ClkPllSrcXTAL);
    CLK_MpllConfig(&stcMpllCfg);

    /* Enable MPLL. */
    CLK_MpllCmd(Enable);
    /* Wait MPLL ready. */
    while(Set != CLK_GetFlagStatus(ClkFlagMPLLRdy))
    {
        ;
    }
    /* Switch driver ability */
    PWC_HS2HP();
    /* Switch system clock source to MPLL. */
    CLK_SetSysClkSource(CLKSysSrcMPLL);
}

/**
 * This function will initial board.
 */
void rt_hw_board_init(void)
{
    System_Clock_Config();

    extern uint32_t SystemCoreClock;
    SysTick_Config(SystemCoreClock/RT_TICK_PER_SECOND);

#ifdef RT_USING_HEAP
    rt_system_heap_init((void*)HEAP_BEGIN, (void*)HEAP_END);
#endif

#ifdef RT_USING_CONSOLE
    rt_hw_uart_init();
    rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif

#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
#endif
}

/***************************************************/

void usart_ll_init(M4_USART_TypeDef *USARTx)
{
    if (USARTx == M4_USART1)
    {
        
    }
    else if (USARTx == M4_USART2)
    {

    }
    else if (USARTx == M4_USART3)
    {
        /* Enable peripheral clock */
        PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_USART3, Enable);
        /* Initialize USART IO */
        PORT_SetFunc(PortE, Pin04, Func_Usart3_Rx, Disable);
        PORT_SetFunc(PortE, Pin05, Func_Usart3_Tx, Disable);
    }
    else if (USARTx == M4_USART4)
    {
        /* Enable peripheral clock */
        PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_USART4, Enable);
        /* Initialize USART IO */
        PORT_SetFunc(PortC, Pin13, Func_Usart4_Rx, Disable);
        PORT_SetFunc(PortH, Pin02, Func_Usart4_Tx, Disable);
    }
    else
    {
        //else
    }
}

void i2c_ll_init(M4_I2C_TypeDef *I2Cx)
{
    if (I2Cx == M4_I2C1)
    {
        /* pin clk etc ... */
        /* Initialize I2C port*/
        PORT_SetFunc(PortC, Pin04, Func_I2c1_Scl, Disable);
        PORT_SetFunc(PortC, Pin05, Func_I2c1_Sda, Disable);

        /* Enable I2C Peripheral*/
        PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_I2C1, Enable); 
    }
    else if (I2Cx == M4_I2C2)
    {
        /* pin clk etc ... */
        /* Initialize I2C port*/
        PORT_SetFunc(PortD, Pin00, Func_I2c2_Scl, Disable);
        PORT_SetFunc(PortD, Pin01, Func_I2c2_Sda, Disable);

        /* Enable I2C Peripheral*/
        PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_I2C2, Enable);
    }
    else if (I2Cx == M4_I2C3)
    {

    }
    else
    {
        //else
    }
}

void get_sys_clk(void)
{
    stc_clk_freq_t sysclk = {0};
    CLK_GetClockFreq(&sysclk);
    rt_kprintf("sysclkFreq = %d\n", sysclk.sysclkFreq);        ///< System clock frequency.
    rt_kprintf("hclkFreq   = %d\n", sysclk.hclkFreq);          ///< Hclk frequency.
    rt_kprintf("exckFreq   = %d\n", sysclk.exckFreq);          ///< Exclk frequency.
    rt_kprintf("pclk0Freq  = %d\n", sysclk.pclk0Freq);         ///< Pclk0 frequency.
    rt_kprintf("pclk1Freq  = %d\n", sysclk.pclk1Freq);         ///< Pclk1 frequency.
    rt_kprintf("pclk2Freq  = %d\n", sysclk.pclk2Freq);         ///< Pclk2 frequency.
    rt_kprintf("pclk3Freq  = %d\n", sysclk.pclk3Freq);         ///< Pclk3 frequency.
    rt_kprintf("pclk4Freq  = %d\n", sysclk.pclk4Freq);         ///< Pclk4 frequency.
}
MSH_CMD_EXPORT(get_sys_clk, display system clk);
